package org.oschina.util;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ReflectUtil {

	private final static Logger logger=LoggerFactory.getLogger(ReflectUtil.class);
	
	private final static String CLASS_PATH=ReflectUtil.class.getResource("/").getPath();
	private static final Method OBJECT_METHODS[]=Object.class.getDeclaredMethods();
	
	/**
	 * 获得不为空的字段名
	 * @param instance
	 * @return
	 */
	public static List<String> getNotNulFieldNames(Object instance)
	{
		List<String> result=new ArrayList<String>();
		Class type=instance.getClass();
		Field fields[]=type.getDeclaredFields();
		for(Field field:fields)
		{
			try
			{
				if(PropertyUtils.getProperty(instance, field.getName())!=null)
					result.add(field.getName());
			}
			catch(Exception e)
			{
				logger.debug("",e);
			}
		}
		return result;
	}
	
	/**
	 * 获得不为空的字段和值
	 * @param instance
	 * @return
	 */
	public static Map<Field,Object> getNotNullFieldAndValue(Object instance)
	{
		Map<Field,Object> result=new HashMap<Field,Object>();
		Class type=instance.getClass();
		Field fields[]=type.getDeclaredFields();
		for(Field field:fields)
		{
			try
			{
				Object value=PropertyUtils.getProperty(instance, field.getName());
				if(value!=null)
					result.put(field, value);
			}
			catch(Exception e)
			{
				logger.debug("",e);
			}
		}
		return result;
	}
	
	/**
	 * 获得类路径
	 * @return
	 */
	public static String getClassPath()
	{
		return CLASS_PATH;
	}
	
	/**
	 * 获得方法参数的注解
	 * @param method
	 * @return
	 */
	public static Annotation[][] getAnnotationsByMethodParameter(Method method)
	{
		return method.getParameterAnnotations();
	}
	
	/**
	 * 获得方法参数某个注解 融入没有注解相应的数组值为空
	 * @param method
	 * @param annotation
	 * @return
	 */
	public static Annotation[] getAnnotationByMethodParameter(Method method,Class annotation)
	{
		int parameterLength=method.getParameterAnnotations().length;
		Annotation annotations[]=new Annotation[parameterLength];
		Annotation pannotation[][]=getAnnotationsByMethodParameter(method);
		
		for(int i=0;i<parameterLength;i++)
		{
			for(int j=0,len=pannotation[i].length;j<len;j++)
			{
				if(pannotation[i][j].annotationType().equals(annotation))
				{
					annotations[i]=pannotation[i][j];
					break;
				}
				
				if(i==len-1)
					annotations[i]=null;
			}
		}
		
		return annotations;
	}
	
	/**
	 * 获得方法
	 * @param clazz
	 * @param methodName
	 * @param args
	 * @return
	 */
	public static Method getMethodByClass(Class clazz,String methodName,Object args[])
	{
		Method methods[]=clazz.getMethods();
		for(Method method:methods)
		{
			if(method.getName().equals(methodName) && args.length==method.getParameterTypes().length)
				return method;
		}
		return null;
	}
	
	/**
	 * 获得字段的某个注解
	 * @param field
	 * @param annotation
	 * @return
	 */
	public static Annotation getAnnotationByField(Field field,Class annotation)
	{
		return field.getAnnotation(annotation);
	}
	
	/**
	 * 获得属性的所有注解
	 * @param field
	 * @return
	 */
	public static Annotation[] getAnnotationsByField(Field field)
	{
		return field.getAnnotations();
	}
	
	/**
	 * 获得方法的所有注解
	 * @param method
	 * @return
	 */
	public static Annotation[] getAnnotationsByMethod(Method method)
	{
		return method.getAnnotations();
	}
	
	/**
	 * 获得方法的某个注解
	 * @param method
	 * @param annotation
	 * @return
	 */
	public static Annotation getAnnotationByMethod(Method method,Class annotation)
	{
		return method.getAnnotation(annotation);
	}
	
	/**
	 * 获得某个类的所有注解
	 * @param clazz
	 * @return
	 */
	public static Annotation[] getAnnotationsByClass(Class clazz)
	{
		return clazz.getAnnotations();
	}
	
	/**
	 * 获得某个类的某个注解
	 * @param clazz
	 * @param annotation
	 * @return
	 */
	public static Annotation getAnnotationByClass(Class clazz,Class annotation)
	{
		return clazz.getAnnotation(annotation);
	}

	/**
	 * 根据注解获得类
	 * @param path
	 * @param annotation
	 * @return
	 */
	public static List<Class> getClassesByPathAndAnnotation(String path,Class annotation) throws ClassNotFoundException
	{
		return getClassesByPathAndAnnotations(path,new Class[]{annotation});
	}
	
	/**
	 * 根据注解获得某个路径下所有类
	 * @param path
	 * @param annotation
	 * @return
	 */
	public static List<Class> getClassesByPathAndAnnotations(String path,Class annotations[]) throws ClassNotFoundException
	{
		List<Class> classes=new ArrayList<Class>();
		List<File> files=FileUtil.listFiles(path,new String[]{"class"},true);
		for(File file:files)
		{
			Class clazz=Class.forName(file.getPath().substring(file.getPath().indexOf("classes")+8).replace("\\",".").replace(".class",""));
			if(annotations!=null && annotations.length>0)
			{
				for(int i=0,len=annotations.length;i<len;i++)
				{
					if(getAnnotationByClass(clazz,annotations[i])!=null)
					{
						classes.add(clazz);
						break;
					}
				}
			}
			else
				classes.add(clazz);
		}
		return classes;
	}
	
	/**
	 * 获得某个路径下所有类
	 * @param path
	 * @return
	 */
	public static List<Class> getClassesByPath(String path) throws ClassNotFoundException
	{
		return getClassesByPathAndAnnotation(path,null);
	}
	
	/**
	 * 判断是否为基本类型
	 * @param clazz
	 * @return
	 */
	public static boolean isBasic(Class clazz)
	{
		if(clazz==null)
			return false;
		
		return (clazz.getName().startsWith("java.lang") || clazz.getName().indexOf(".")==-1);
	}
	
	/**
	 * 判断是否为Object的方法
	 * @param method
	 * @return
	 */
	public static boolean isObjectMethod(Method method)
	{
		for(int i=0;i<OBJECT_METHODS.length;i++)
		{
			if(OBJECT_METHODS[i].getName().equals(method.getName()))
				return true;
		}
		return false;
	}
}